# -*- coding: utf-8 -*-

import asyncio
import json
import socket
import threading
import time
import uuid
from centre import Centre
from log import getLogger

logger = getLogger(__name__)

clien_list = {}
lost_time = 20  # 判断断开连接的超时时间
coded_format = 'utf-8'

loop = asyncio.get_event_loop()
centre = Centre(loop)


# 客户端注册
def clien_reg(sn):
    if not clien_list.get(sn):
        logger.info(sn + ': 上线')
        centre.add_alarm_record(sn, 1)
    clien_list[sn] = {"time": time.time(), "state": 1}
    return sn


def check_hart(clien_list, delay, lost_time):
    while True:
        for sn in clien_list:
            if abs(clien_list[sn]['time'] - time.time()) > lost_time:
                logger.info(sn + ': 断开')
                clien_list[sn]['state'] = 0
                del clien_list[sn]
                centre.add_alarm_record(sn, 2)
                break
            else:
                clien_list[sn]['state'] = 1
                # logger.info(sn + '正常')
        time.sleep(delay)


def send_json(conn, code, msg, data=None):
    d = dict()
    d['code'] = code
    d['msg'] = msg
    if data:
        d['data'] = data
    else:
        d['data'] = ''
    try:
        conn.sendall(json.dumps(d).encode(coded_format))
    except:
        pass


def message_handle(conn, addr):
    sole_id = str(uuid.uuid4()).upper()
    logger.info('Connected by' + str(addr))
    logger.info(sole_id)
    conn.sendall(json.dumps({'sole_id': sole_id}).encode(coded_format))
    while True:
        try:
            data = conn.recv(1024)

            if len(data) == 0:
                logger.warning("Client disconnect: " + str(addr))
                conn.close()
                break

            try:
                dedata_json = json.loads(data, encoding=coded_format)

                if dedata_json.get('cmd', '') == 'heartbeat':
                    clien_reg(dedata_json["sn"])
                    send_json(conn, 0, 'ok')
            except json.decoder.JSONDecodeError:
                send_json(conn, -1, 'The data format is not json')
            except AttributeError:
                send_json(conn, -1, 'error')

        except ConnectionResetError:
            logger.warning('远程主机强迫关闭了一个现有的连接。')
            break
        except Exception as e:
            logger.warning(e)
            break


def serve_loop(socket):
    while True:
        conn, addr = socket.accept()
        t = threading.Thread(target=message_handle, args=(conn, addr))
        t.setDaemon(True)
        t.start()


def init():
    logger.info('System up and running...')
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind(('', 8881))
    s.listen(5)
    threading.Thread(target=check_hart,
                     args=(clien_list, 5, lost_time),
                     name="check_hart").start()
    serve_loop(s)


if __name__ == "__main__":
    init()
